package com.cimu.xinge.service.impl;

import com.alibaba.fastjson.JSON;
import com.cimu.xinge.entity.User;
import com.cimu.xinge.enums.PushModelEnum;
import com.cimu.xinge.properties.XinGePushConfig;
import com.cimu.xinge.service.XinGePushService;
import com.tencent.xinge.Message;
import com.tencent.xinge.MessageIOS;
import com.tencent.xinge.TimeInterval;
import com.tencent.xinge.XingeApp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Title: XinGePushServiceImpl
 * Copyright: Copyright (c) 2017
 * <p>
 * date 2018年12月18日 19:21
 */
@Slf4j
@Service
public class XinGePushServiceImpl implements XinGePushService {
    private static final Pattern TIME_REGEX = Pattern.compile("^([01]?\\d|2[0123]):([0-5]?[0-9]) ?- ?([01]?\\d|2[0123]):([0-5]?[0-9])$");
    private Map<String, TimeInterval> cachedAcceptTime = new ConcurrentHashMap<String, TimeInterval>();

    private XingeApp xinge;
    @Autowired
    private XinGePushConfig xinGePushConfig;

    @PostConstruct
    private void init() {
        xinge = new XingeApp(xinGePushConfig.getAccessId(), xinGePushConfig.getSecretKey());
    }

    @Override
    public void pushSingleDevice(User user, String title, String content, String sendTime, String acceptTime) {
        log.info("[pushSingleDevice]入参user=[{}],title=[{}],content=[{}]," +
                "sendTime=[{}],acceptTime=[{}]", JSON.toJSONString(user), title, content, sendTime, acceptTime);
        if (StringUtils.isAnyBlank(title, content, user.getPushToken(), user.getDeviceType())) {
            log.warn("[pushSingleDevice]推送内容不能为空");
            return;
        }
        JSONObject ret = null;
        //判断用户使用什么手机，android和ios调用方法不一样
        if (PushModelEnum.IOS.getKey().equalsIgnoreCase(user.getDeviceType())) {
            MessageIOS messageIOS = new MessageIOS();
            messageIOS.setType(MessageIOS.TYPE_APNS_NOTIFICATION);
            messageIOS.setAlert(content);
            messageIOS.setBadge(1);
            messageIOS.setSound("beep.wav");
            if (StringUtils.isNotBlank(sendTime)) {
                messageIOS.setSendTime(sendTime);
            }
            messageIOS.addAcceptTime(getTimeInterval(acceptTime));
            ret = xinge.pushSingleDevice(user.getPushToken(), messageIOS, getEnvironment());
        } else {
            Message message = new Message();
            message.setTitle(title);
            message.setContent(content);
            if (StringUtils.isNotBlank(sendTime)) {
                message.setSendTime(sendTime);
            }
            message.addAcceptTime(getTimeInterval(acceptTime));
            message.setType(Message.TYPE_NOTIFICATION);
            ret = xinge.pushSingleDevice(user.getPushToken(), message);
        }
        log.info("[pushSingleDevice]推送返回值：{}", ret);
        //TODO 可以把推送请求和返回保存到一张日志表，用来排查问题
    }

    @SuppressWarnings("unchecked")
    @Override
    public void pushMultiDevice(List<String> tokenPushList, Long pushId) {
        log.info("[pushMultiDevice]入参tokenPushList=[{}],pushId=[{}]",
                JSON.toJSONString(tokenPushList), pushId);
        if (pushId == null || CollectionUtils.isEmpty(tokenPushList)) {
            log.warn("[pushMultiDevice]推送内容不能为空");
            return;
        }
        JSONObject result = xinge.pushDeviceListMultiple(pushId, tokenPushList);
        log.info("[pushMultiDevice]推送返回值：{}", result);
    }

    @Override
    public Long createMultiDevicePush(String title, String content, String sendTime, PushModelEnum pushModel) {
        log.info("[createMultiDevicePush]入参:title=[{}],content=[{}],sendTime=[{}],pushModel=[{}]",
                title, content, sendTime, pushModel);
        JSONObject ret;
        if (PushModelEnum.IOS == pushModel) {
            MessageIOS messageIOS = new MessageIOS();
            messageIOS.setType(MessageIOS.TYPE_APNS_NOTIFICATION);
            messageIOS.setAlert(content);
            messageIOS.setBadge(1);
            messageIOS.setSound("beep.wav");
            if (StringUtils.isNotBlank(sendTime)) {
                messageIOS.setSendTime(sendTime);
            }
            ret = xinge.createMultipush(messageIOS, getEnvironment());
        } else {
            Message message = new Message();
            message.setExpireTime(0);
            message.setTitle(title);
            message.setContent(content);
            message.setType(Message.TYPE_NOTIFICATION);
            if (StringUtils.isNotBlank(sendTime)) {
                message.setSendTime(sendTime);
            }
            ret = xinge.createMultipush(message);
        }
        log.info("[createMultiDevicePush]调用createMultipush返回值：{}", ret);
        if (ret != null && ret.getInt("ret_code") == 0) {
            return ret.getJSONObject("result").getLong("push_id");
        }
        return null;
    }

    /**
     * 获取环境配置
     *
     * @return int 1表示生产环境 2表示开发环境
     */
    private int getEnvironment() {
        //ios有区分生产和开发，可以根据自己的打包环境进行判断
        //TODO 这边写的伪代码
        return 1 == 2 ? XingeApp.IOSENV_PROD : XingeApp.IOSENV_DEV;
    }

    /**
     * 获取允许推送时间段
     *
     * @param acceptTime 允许推送时间段
     * @return TimeInterval 时间段
     */
    private TimeInterval getTimeInterval(String acceptTime) {
        if (StringUtils.isBlank(acceptTime)) {
            acceptTime = "9:00-20:00";
        }
        return buildAcceptTime(acceptTime);
    }

    /**
     * 封装允许推送时间的对象
     *
     * @param ranges 13:00 - 14:00
     * @return TimeInterval TimeInterval
     */
    private TimeInterval buildAcceptTime(String ranges) {
        TimeInterval timeInterval = cachedAcceptTime.get(ranges);
        if (timeInterval != null) {
            return timeInterval;
        }
        Matcher matcher = TIME_REGEX.matcher(ranges);
        if (!matcher.matches()) {
            throw new RuntimeException("信鸽推送时间设置错误");
        }
        // 分析出日期
        String shour = matcher.group(1);
        String smin = matcher.group(2);
        String ehour = matcher.group(3);
        String emin = matcher.group(4);
        timeInterval = new TimeInterval(Integer.parseInt(shour), Integer.parseInt(smin),
                Integer.parseInt(ehour), Integer.parseInt(emin));
        cachedAcceptTime.put(ranges, timeInterval);
        return timeInterval;
    }

}
